from django.shortcuts import render,redirect
#导包
from django.http import HttpResponse,HttpResponseRedirect,JsonResponse
#导入类视图
# from django.utils.deprecation import MiddlewareMixin
from django.views import View

#from myapp.models import User
from django.core.serializers import serialize
from rest_framework.response import Response
from rest_framework.views import APIView
#导入加密库
import hashlib
#导入图片库
#绘画库
from PIL import ImageDraw
#字体库
from PIL import ImageFont
#图片库
from PIL import Image
#随机库
import random
#文件流
import io

import requests

#导入上传文件夹配置

from mydjango.settings import UPLOAD_ROOT
import os

#导入原生sql模块
from django.db import connection

import jwt

#导入redis数据库
import redis

#导入时间模块
import time

#导入公共目录变量
from mydjango.settings import BASE_DIR

#导包
from django.db.models import Q,F

#导入dwebsocket的库
from dwebsocket.decorators import accept_websocket
import uuid

from myapp.models import *
from myapp.ser import *
#导入正则
import re

import hmac
import base64
from hashlib import sha256
import urllib
import json

# 导入中间件
from django.utils.deprecation import MiddlewareMixin

# 自定义中间件
class MyMiddleware(MiddlewareMixin):
    def process_request(self, request):
        # print('过滤中间件')
        #
        # # 获取路由  指定走userinfo才会运行
        # if request.path_info.startswith('/userinfo/'):
        #     return JsonResponse({'message': '您篡改了uid'}, safe=False, json_dumps_params={'ensure_ascii': False, 'indent': 4})
            # return HttpResponse(json.dumps({'message': '您篡改了uid'}, ensure_ascii=False, indent=4), content_type='application/json')
        pass

    def process_view(self, request, view_func, view_args, view_kwargs):
        pass

    def process_exception(self, request, exception):
        pass

    def process_response(self, request, response):
        return response


# redis
import redis
# 定义IP地址和端口
host = '127.0.0.1'
port = 6379
# 定义链接对象
r = redis.Redis(host=host, port=port)


# 导入dwebsocket的库
from dwebsocket.decorators import accept_websocket
import uuid
from myapp.models import *
from django.utils.deprecation import MiddlewareMixin
import pymongo
from myapp.ser import *
r = redis.Redis('localhost', 6379)
conn = pymongo.MongoClient('localhost', 27017)
db = conn.md
table = db.goods_img

# 商品评论
class CommentInsert(APIView):
    conn = pymongo.MongoClient('localhost', 27017)
    db = conn.md
    table = db.comment
    def get(self,reuqest):
        gid = reuqest.GET.get('gid',None)
        print(gid)
        comments = self.table.find({'gid':gid},{'_id':0}).sort([("_id",pymongo.DESCENDING)])
        # comments=Comment.objects.filter(gid= gid).all().order_by('-id')
        # users= User.objects.values('id','username')
        # comment_Ser= CommentSer(comments,many=True)
        # # user_ser= Userser(users,many=True)
        return Response({'code':200,'data':list(comments)})
        # return Response({'code':200,'data':comment_Ser.data,'udata':users})

    def post(self,request):
        # 获取客户端ip
        if 'HTTP_X_FORWARDED_FOR' in request.META:
            ip = request.META.get('HTTP_X_FORWARDED_FOR')
        else:
            ip= request.META.get('REMOTE_ADDR')
        print(ip)
        # 30 秒内只能评论三次
        try:
            if r.llen(ip)>3 :
                return Response({'code':403,'msg':'您评论过快'})
        except Exception as e:
            pass

        try:
            self.table.insert({
                'username': request.POST.get('username',None),
                'gid':request.POST.get('gid'),
                'content':request.POST.get('content'),
            })
            r.lpush(ip, 1)
            r.expire(ip, 30)
        except :
            pass
        # 初始化参数
        # comment = CommentSer(data=request.data)
        # 验证字段
        # if comment.is_valid():
            # 进行入库操作
            # comment.save()
            # 设置评论间隔
            # r.lpush(ip,1)
            # r.expire(ip,30)

        return Response({'code':200,'msg':'评论成功'})

# 商品详情页
class Goodinfo(APIView):
    def get(self,request):
        id=request.GET.get('id')
        goods=Goods.objects.get(pk=id)
        # 判断是否有详情图片
        info_img=[]
        info_video=''
        if goods.info_imgs ==1:
            info_img=table.find_one({"name":goods.name})['imgs']
            info_video=table.find_one({"name":goods.name})['video']
        goods_ser=GoodsSer(goods)

        return Response({"data":goods_ser.data,"info_imgs":info_img,'info_video':info_video})

# 搜索接口
class Search(APIView):
    def get(self,request):
        # 检索字段
        text = eval(request.GET.get('text',None))
        # 建立游标对象

        sql=""
        for val in text:
            # 拼接sql语句
            sql += "or name like '%%%s%%'"%val

        cursor=connection.cursor()
        # 执行sql
        cursor.execute("select name,id,img,price from goods where %s"%sql[2:])
        # 查询
        res=dictfetch(cursor)
        count=len(res)
        return Response({'msg':text,"data":res,'total':count})

#  格式化结果集
def dictfetch(cursor):
    # 声明描述符 description 字段名
    desc= cursor.description
    # 重组结果
    return [dict(zip([col[0] for col in desc],row))
        for row in cursor.fetchall()
    ]


# 商品详情页
class GoodInfo(APIView):
    def get(self, request):
        id = request.GET.get('id', None)
        # 单一查询不需要many=true
        good = Goods.objects.filter(pk=id).first()
        # 序列化 单一查询不需要many=true
        good_ser = GoodsSer(good)
        # 返回
        return Response(good_ser.data)


# 商品列表页
class GoodsList(APIView):
    def get(self, request):
        # 检索字段
        text = request.GET.get('text', None)

        # 排序字段
        coloum = request.GET.get('coloum', None)
        # 排序方案
        sort_order = request.GET.get('order', None)

        # 获取当前页
        page = request.GET.get('page', 1)
        # 每页显示个数
        size = request.GET.get('size', 5)
        # 计算从哪开始切
        data_start = (int(page)-1) * int(size)
        # 计算切到哪
        data_end = (int(page)) * int(size)

        # 查询  分页切片操作  .order_by('')排序
        if coloum:
            goods = Goods.objects.all().order_by(sort_order + coloum)[data_start:data_end]
        else:
            goods = Goods.objects.all()[data_start:data_end]

        # 判断是否进行模糊查询
        if text:
            goods = Goods.objects.filter(Q(name__contains=text) | Q(desc__contains=text)).all()[data_start:data_end]
            count = Goods.objects.filter(Q(name__contains=text) | Q(desc__contains=text)).count()
        else:
            # 查询所有商品个数  直接使用count()
            count = Goods.objects.count()

        # 序列化
        goods_ser = GoodsSer(goods, many=True)
        # 返回
        return Response({'data': goods_ser.data, 'total': count})


#商品分类接口
class CategoryList(APIView):
    def get(self, request):
        category = Category.objects.all()

        category_ser = CategorySer(category, many=True)

        return Response(category_ser.data)


#商品入库接口
class InsertGoods(APIView):
    def get(self, request):
        #接参
        name = request.GET.get("name", None)
        price = request.GET.get("price", None)
        params = request.GET.get("params", None)
        cid = request.GET.get('cid', None)
        #排重操作
        goods = Goods.objects.filter(name=name).first()
        if goods:
            return Response({'code': 403, 'message': '您已经添加过该商品'})
        #入库
        goods = Goods(name=name, price=price, params=params, cid = cid)
        goods.save()
        return Response({'code': 200, 'message': '添加商品成功'})


# 轮播图后台接口
class GetCarousel(APIView):

    def get(self, request):
        # 读库
        carousels = Carousel.objects.all()

        # 序列化操作
        carousels_ser = CarouselSer(carousels, many=True)

        return Response(carousels_ser.data)


import upyun

def ding_url(request):
    appid = 'dingoa0h5pvdykgqobbom5'
    redirect_uri = 'http://localhost:8000/dingding_back/'
    return redirect('https://oapi.dingtalk.com/connect/qrconnect?appid='+appid+'&response_type=code&scope=snsapi_login&state=STATE&redirect_uri='+redirect_uri)

#定义权限检测装饰器
def my_decorator(func):
    def wrapper(request,*args,**kwargs):
        #接受参数
        uid = request.GET.get('uid',None)
        myjwt = request.GET.get('jwt',None)
        encode_jwt = jwt.decode(myjwt, 'qwe123', algorithms=['HS256'])
        # 比对
        if int(uid) != int(encode_jwt['data']['uid']):
            return Response({'code': 401, 'message': '您的密钥无权限'})
        return func(request,*args,**kwargs)
    return wrapper

from django.utils.decorators import method_decorator

#获取用户信息
class UserInfo(APIView):
    @method_decorator(my_decorator)
    def get(self,request):
        #接受参数
        uid = request.GET.get('uid',None)
        #查询数据库
        user = User.objects.get(id=int(uid))
        if user.img == "":
            user.img = 'sina.png'
        #返回
        return Response({'img':user.img,'phone':user.phone})


#创建又拍云目录
class Upy(View):
    def get(self,request):
        upmkdir = request.GET.get('upmkdir')
        up = upyun.UpYun('1907md', username='zym', password='0Fr6JYeS9L0i9RnfPNYKOFVOeH8EVQzj')
        up.mkdir('/%s/'%upmkdir)
        return HttpResponse({'message':'创建成功'})
    def delete(self,request):
        filename = request.GET.get('filename')
        up = upyun.UpYun('1907md', username='zym', password='0Fr6JYeS9L0i9RnfPNYKOFVOeH8EVQzj')
        up.delete('/'+filename)
        return HttpResponse({'message':'删除成功'})

# 定义文件上传类
class Ypyun(APIView):
    def post(self,request):
        img = request.FILES.get('file')
        up = upyun.UpYun('1907md',username='zym',password='0Fr6JYeS9L0i9RnfPNYKOFVOeH8EVQzj')
        headers = {'x-gmkerl-rotate': '180'}
        for chunk in img.chunks():
            res = up.put('/'+img.name,chunk,checksum=True,headers=headers)
        return HttpResponse(json.dumps({'filename':img.name}),content_type='application/json')


# 七牛云token
from qiniu import Auth
class Qiniu(APIView):
    def get(self, request):
        # 声明认证对象
        q = Auth('E2IZM3koC1GR1DUqJHactmixzdyZZhx0edBKqDsk', 'GDnMkvRoE_kFhCSuvdqQj0VcNsRDOHzYJJ_bVd0_')
        # 获取token
        token = q.upload_token('upload1907rgzn')
        return Response({'token': token})

#导入上传文件夹配置
from mydjango.settings import UPLOAD_ROOT
# 定义文件上传通用类
class UploadFile(APIView):
    def post(self, request):
        # 接收参数
        uid = request.POST.get('uid')
        myfile = request.FILES.get('file')
        # print(myfile)

        user = User.objects.filter(pk=int(uid)).first()
        if user:
            # 建立文件流对象
            # f = open(os.path.join(UPLOAD_ROOT, '', myfile.name.replace(" ", '')), 'wb')
            f = open(os.path.join(UPLOAD_ROOT, '', myfile.name), 'wb')
            # 写入
            for chunk in myfile.chunks():
                f.write(chunk)
                user.img = myfile.name
                f.close()
            user.save()
            return Response({'code': 200, 'message': '添加成功', 'img': user.img})
        return Response({'code': 300, 'message': '添加失败'})


# 钉钉回调
def dingding(request):
    # 获取code
    code = request.GET.get("code")
    # print(code)

    t = time.time()
    # 时间戳
    timestamp = str((int(round(t * 1000))))
    appSecret = '_iNQfR2ba0d1NTl57vAyHLAHGf7MDzWFvLSxI3__d_02UPPgpsKy4zkUi2Eah8nb'
    # 构造签名
    signature = base64.b64encode(
        hmac.new(appSecret.encode('utf-8'), timestamp.encode('utf-8'), digestmod=sha256).digest())
    # 请求接口，换取钉钉用户名
    payload = {'tmp_auth_code': code}
    headers = {'Content-Type': 'application/json'}
    res = requests.post('https://oapi.dingtalk.com/sns/getuserinfo_bycode?signature=' + urllib.parse.quote(
        signature.decode("utf-8")) + "&timestamp=" + timestamp + "&accessKey=dingoavtrejmdlyxnnyhvi",
                        data=json.dumps(payload), headers=headers)


    print(res.json())
    return HttpResponse(res.text)

# 新浪微博回调,换取token和uid
def wb_back(request):
    # 获取code
    code = request.GET.get('code')
    # 定义微博认证地址
    access_token_url = 'https://api.weibo.com/oauth2/access_token'
    # 参数
    re = requests.post(
        access_token_url,
        data={
            'client_id': '3035970630',
            'client_secret': 'cf1266f23c63aa9f65b3f9182b4e2eaa',
            'grant_type': 'authorization_code',
            'code': code,
            'redirect_uri': 'http://127.0.0.1:8000/md_admin/weibo'
        }
    )
    print(re.json())

    # 获取新浪微博昵称
    res = requests.get('https://api.weibo.com/2/users/show.json', params={
        'access_token': re.json()['access_token'], 'uid': re.json()['uid']
    })
    # print(res.json())
    sina_id = ''
    user_id = ''

    # 判断是否用新浪微博登录过  唯一定义为新浪id用户名
    user = User.objects.filter(username=str(res.json()['id'])).first()
    if user:
        # 代表曾经登录过
        sina_id = user.username
        user_id = user.id
    else:
        # 首次登录 入库新浪微博账号
        user = User(username=str(res.json()['id']), password='')
        user.save()
        user = User.objects.filter(username=str(res.json()['id'])).first()
        sina_id = user.username
        user_id = user.id
    # print(sina_id, user_id)

    # 重定向
    return redirect('http://localhost:8080?sina_id='+str(sina_id)+'&uid='+str(user_id))



# 自定义图片验证码
class MyCode(View):
    # 定义rgb随机颜色
    def get_random_color(self):
        R = random.randrange(255)
        G = random.randrange(255)
        B = random.randrange(255)
        return (R, G, B)
    # 定义图片视图
    def get(self, request):
        # 画布
        img_size = (120, 50)
        # 定义图片对象
        image = Image.new('RGB', img_size, 'white')
        # 定义画笔
        draw = ImageDraw.Draw(image, 'RGB')
        # 定义随机生成数字
        source = '0123456789'
        # 接收容器
        code_str = ''
        # 进入循环绘制， 获取随机字符4个
        for i in range(4):
            # 获取字母颜色
            text_color = self.get_random_color()
            # 获取随机下标
            tmp_num = random.randrange(len(source))
            # 随机字符串
            random_str = source[tmp_num]
            # 装入容器
            code_str += random_str
            # 绘制字符串
            draw.text((10+30*i, 20), random_str, text_color)
        # 获取缓存区 使用io模块
        buf = io.BytesIO()
        # 将临时图片保存到缓存
        image.save(buf, 'png')
        # 保存随机码
        r.set('code', code_str)
        # 保存session
        request.session['code'] = code_str
        # print(r.get('code'))
        # 返回图片
        return HttpResponse(buf.getvalue(), 'image/png')

# md5加密方法
def make_password(mypass):
    # 生成md5对象
    md5 = hashlib.md5()
    # 转码操作
    mypass_utf8 = str(mypass).encode(encoding='utf-8')
    # 加密操作
    md5.update(mypass_utf8)
    # 返回密文
    return md5.hexdigest()

# 修改密码
class UpdataPas(APIView):
    def get(self, request):
        uid = request.GET.get('uid')
        password = request.GET.get('password')
        user = User.objects.filter(id=uid).first()
        if user:
            user.password = make_password(password)
            user.save()
            return Response({'code': 200, 'message': '修改成功'})
        return Response({'code': 500, 'message': '修改失败'})


# 登录接口
class Login(APIView):
    def get(self, request):
        # 接收参数
        username = request.GET.get('username', None)
        password = request.GET.get('password', None)
        phone = request.GET.get('phone', None)
        code = request.GET.get('code', None)
        # 查询
        user = User.objects.filter(Q(username=username) | Q(phone=phone), password=make_password(password)).first()

        # 获取验证码
        redis_code = r.get('code')
        # 转码
        redis_code = redis_code.decode('utf-8')

        # 从session中取值
        # session_code = request.session.get('code', None)
        # print(session_code)

        # 判断验证码是否正确
        if code != redis_code:
            return Response({'code': 500, 'message': '验证码错误'})



        # 次数加1
        r.lpush(username, 1)
        print(r.llen(username))

        # 判断密码输入是否大于5次
        if r.llen(username) > 5:
            # 过期时间
            r.expire(username, 20)
            # print(r.ttl(password))
            return Response({'code': 300, 'message': '您的账号已锁定'})

        if user:
            encode_jwt = jwt.encode({'uid': user.id}, 'fjk', algorithm='HS256')
            encode_str = str(encode_jwt, 'utf-8')
            return Response(
                {'code': 200, 'message': '登录成功', 'uid': user.id, 'username': user.username, 'jwt': encode_str})
        return Response({'code': 300, 'message': '账号或密码错误'})

# 注册接口
class Register(APIView):
    def get(self, request):
        # 接收参数
        username = request.GET.get('username', None)
        password = request.GET.get('password', None)
        phone = request.GET.get('phone', None)

        # 排重操作
        user = User.objects.filter(username=username).first()
        if user:
            return Response({'code': 403, 'message': '该用户名已存在'})

        if not re.match(r"^1[358]\d{9}$", phone):
            return Response({'code': 300, 'message': '手机号格式不正确'})

        # 入库
        user = User(username=username, password=make_password(password), phone=phone)

        # 保存结果
        user.save()

        return Response({'code': 200, 'message': '恭喜注册成功'})

